package com.aididi.controller;

import com.aididi.dto.LogDto;
import com.aididi.entity.es.EsLog;
import com.aididi.entity.mysql.MysqlLog;
import com.aididi.repository.es.EsLogRepository;
import com.aididi.repository.mysql.LogRepository;
import com.aididi.util.PageResult;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.ScoreSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * @Auther: zx.xu
 * @Description:
 */
@RestController
@RequestMapping("/log")
@Slf4j
public class LogController {

    @Autowired
    private LogRepository logRepository;

    @Autowired
    private EsLogRepository esLogRepository;

    @Autowired
    private TransportClient client;

    @GetMapping("/logs")
    public PageResult<MysqlLog> blog(@RequestParam(required = false) Integer page,
                                     @RequestParam(required = false) Integer size){
        page = page == null || page < 2 ? 0 : page - 1;
        size = size == null || size < 0 ? 5 : size;
        //判断排序类型及排序字段
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        PageRequest pageRequest =  PageRequest.of(page,size,sort);
        Page<MysqlLog> logPage= logRepository.findAll(pageRequest);
        //总条数
        long totalCount =  logPage.getTotalElements();
        //数据列表
        List<MysqlLog> logList =  logPage.getContent();
        //总页数
        int pages = logPage.getTotalPages();
        PageResult<MysqlLog> result = new PageResult<>();
        result.setCount(totalCount);
        result.setPage(pages);
        result.setResult(logList);
        return result;
    }

    @PostMapping("/search")
    public Object esBlog(@RequestBody LogDto dto){
        Map<String,Object> map = new HashMap<>();
        String type = dto.getType();
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        if("mysql".equalsIgnoreCase(type)){
            List<MysqlLog> mysqlLogList = logRepository.queryList(dto.getKeyword());
            map.put("logList", mysqlLogList);
        }else if("es".equalsIgnoreCase(type)){
            //实现关键字搜索
            BoolQueryBuilder builder =  QueryBuilders.boolQuery();
            //matchQuery:代表模糊匹配,termQuery：精确匹配
            //should:表示匹配到name或者desc中的任一字段就行,相当于or，must：表示name和desc都必须满足,相当于and
            builder.should(QueryBuilders.matchQuery("name",dto.getKeyword()));
            builder.should(QueryBuilders.matchQuery("desc",dto.getKeyword()));
            String query =  builder.toString();
            log.info("searchcontent--{}",query);
            Page <EsLog> search = (Page<EsLog>) esLogRepository.search(builder);
            //返回搜索内容querydsl
            List<EsLog> esLogList = search.getContent();
            log.info("logContent--{}",esLogList);
            //设置高亮显示的字段
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.field("name");
            highlightBuilder.field("desc");
            highlightBuilder.preTags("<strong><font style=\"color: red\">");//设置高亮显示前缀
            highlightBuilder.postTags("</font></strong>");//设置高亮显示后缀
            //下面这两项,如果你要高亮如文字内容等有很多字的字段,必须配置,不然会导致高亮不全,文章内容缺失等
            highlightBuilder.fragmentSize(800000); //最大高亮分片数
            highlightBuilder.numOfFragments(0); //从第一个分片获取高亮片段
            //读取索引
            SearchRequestBuilder requestBuilder = client.prepareSearch(getIndexName()).setTypes(getTypeName());
            requestBuilder.setQuery(builder);
            requestBuilder.highlighter(highlightBuilder);
            //根据创建时间倒序排序
            FieldSortBuilder fieldSortBuilder =  SortBuilders.fieldSort("createtime").order(SortOrder.DESC);
            requestBuilder.addSort(new ScoreSortBuilder());//根据查询相关度得分进行排序
            requestBuilder.addSort(fieldSortBuilder);//再根据时间进行排序
            //获取到当前页为止共多少条
            int from  = dto.getPage()-1 * dto.getDefaultSize();
            //分页
            requestBuilder.setFrom(from).setSize(dto.getDefaultSize());

            log.info("查询结果：${}",requestBuilder.toString());

            SearchResponse response = requestBuilder.get();
            SearchHits hits = response.getHits();
            //记录总数
            long totalHits = hits.getTotalHits();

            Iterator<SearchHit> iterator = hits.iterator();
            Map _m;
            List<Map<String,Object>> list = new ArrayList();
            while (iterator.hasNext()){
                SearchHit next = iterator.next();
                //获取文档内容转为map对象
                Map<String,Object> sourceAsMap = next.getSourceAsMap();
                //取出高亮字段,start
                Map<String, HighlightField> highlightFields = next.getHighlightFields();
                HighlightField temp;
                _m = new HashMap(8);
                _m.put("name", StringUtils.isEmpty(sourceAsMap.get("name"))?"":sourceAsMap.get("name"));
                _m.put("desc", StringUtils.isEmpty(sourceAsMap.get("desc"))?"":sourceAsMap.get("desc"));
                temp = highlightFields.get("name");
                if (null != temp && null != temp.fragments()) {
                    Text[] fragments = temp.fragments();
                    _m.put("name", fragments[0].toString());
                }
                temp = highlightFields.get("desc");
                if (null != temp && null != temp.fragments()) {
                    Text[] fragments = temp.fragments();
                    _m.put("desc", fragments[0].toString());
                }
                    list.add(_m);
                //取出高亮字段,end
            }

            map.put("logList",list);
            if(totalHits>0){
                map.put("total",totalHits);
            }
        }else{
            return "i no!!";
        }
        stopWatch.stop();
        Long totalTimeMillis = stopWatch.getTotalTimeMillis();
        map.put("totalMillis",totalTimeMillis);
        return map;
    }

    @GetMapping("/{id}")
    public Object getLogById(@PathVariable Integer id){
        Optional<MysqlLog> log = logRepository.findById(id);
        return log.get();
    }

    /**
     * 获取es索引名
     * @return
     */
    private String getIndexName(){
      Class<EsLog> cls= EsLog.class;
      Document document =  cls.getAnnotation(Document.class);
      if(null != document){
          return document.indexName();
      }
      return null;
    }

    /**
     * 获取es对应索引下的type
     * @return
     */
    private String getTypeName(){
        Class<EsLog> cls= EsLog.class;
        Document document =  cls.getAnnotation(Document.class);
        if(null != document){
            return document.type();
        }
        return null;
    }


}
